WAFER_DIR = ../..
WAFER_BUILD_DIR = $(WAFER_DIR)/build
WAFER_FRONTEND := $(WAFER_BUILD_DIR)/bin/wafer-frontend
WAFER_OPT = $(WAFER_BUILD_DIR)/bin/wafer-opt
WAFER_TRANSLATE = $(WAFER_BUILD_DIR)/bin/wafer-translate

LLVM_BIN_DIR = $(WAFER_DIR)/3rdparty/llvm/build/bin
CLANG = $(LLVM_BIN_DIR)/clang++
PTXAS = /usr/local/cuda/bin/ptxas
FATBINARY = /usr/local/cuda/bin/fatbinary
CICC = /usr/local/cuda/nvvm/bin/cicc

OUT_DIR = build
INC_DIR := $(realpath ../../include)
LIB_DIR := $(realpath ../../build/lib)
LLVM_PRJ_DIR := $(realpath ../../3rdparty/llvm)
LLVM_CLANG_INC_DIR := $(LLVM_PRJ_DIR)/build/lib/clang/17/include

CXX := /usr/bin/g++
OPENSSL_DIR := $(realpath ../../3rdparty/openssl/build)
OPENSSL_LIB_DIR := $(OPENSSL_DIR)/lib64
OPENSSL_INC_DIR := $(OPENSSL_DIR)/include

DESIGN_JSON_FILE := ./design2.json

export PRINT_SCHEDULE=ON


.PHONY: all
all: $(OUT_DIR)/example.o $(OUT_DIR)/host_ctrl.o $(OUT_DIR)/wafer_gpu.out
	@mkdir -p $(@D)
	$(CLANG) $(OUT_DIR)/example.o $(OUT_DIR)/host_ctrl.o \
	 			-L$(WAFER_DIR)/3rdparty/llvm/build/lib -lmlir_c_runner_utils \
	            -L $(WAFER_BUILD_DIR)/lib -lwafer_sst_runtime \
				-L $(LIB_DIR)/CGRAAPI -lwafer_cgra_api \
				-Wl,-rpath=$(WAFER_DIR)/3rdparty/llvm/build/lib:$(WAFER_BUILD_DIR)/lib \
				-o $(OUT_DIR)/sha1_crack
	@echo "Build successfully"

.PHONY: cpu-only
cpu-only: $(OUT_DIR)/example.o $(OUT_DIR)/host_ctrl.o
	@mkdir -p $(@D)
	$(CLANG) $(OUT_DIR)/example.o $(OUT_DIR)/host_ctrl.o \
	 			-L$(WAFER_DIR)/3rdparty/llvm/build/lib -lmlir_c_runner_utils \
	            -L$(WAFER_BUILD_DIR)/lib -lwafer_sst_runtime \
				-L $(LIB_DIR)/CGRAAPI -lwafer_cgra_api \
				-Wl,-rpath=$(WAFER_DIR)/3rdparty/llvm/build/lib:$(WAFER_BUILD_DIR)/lib \
				-o $(OUT_DIR)/sha1_crack
	@echo "Build (CPU Only) successfully"

$(OUT_DIR)/host_ctrl.o: $(OUT_DIR)/op_sha1crack.ll 
	$(LLVM_BIN_DIR)/llc -mtriple=x86_64-unknown-linux-gnu -mattr=+sha $< --filetype=obj -o $@

$(OUT_DIR)/example.o: SHA1Example.cpp
	@mkdir -p $(@D)
	$(CLANG)  -c $< -I $(WAFER_DIR)/include -o $@

$(OUT_DIR)/op_sha1crack.ll: $(OUT_DIR)/sha1crack_schedule.mlir
	DESIGN_JSON_FILE=${DESIGN_JSON_FILE} $(WAFER_OPT) $^ \
		--lower-hyper-sstmemcpy \
		--sst-lower-hyper \
		--lower-crypto-padmessage \
		--lower-cryptosha1-without-SHA1ISA \
		--lower-crypto-to-cgra \
		--llvm-request-c-wrappers \
		--convert-scf-to-cf \
		--convert-arith-to-llvm \
		--finalize-memref-to-llvm \
		--convert-vector-to-llvm \
		--lower-sst-to-llvm \
		--convert-func-to-llvm \
		--reconcile-unrealized-casts | \
	$(WAFER_TRANSLATE) --wafer-to-llvmir -o $@

$(OUT_DIR)/sha1crack_schedule.mlir: $(OUT_DIR)/sha1crack_hyper.mlir
	DESIGN_JSON_FILE=${DESIGN_JSON_FILE} $(WAFER_OPT) $^ --sst-device-schedule -o $@


$(OUT_DIR)/sha1crack_hyper.mlir: $(OUT_DIR)/sha1crack.mlir
	DESIGN_JSON_FILE=${DESIGN_JSON_FILE} $(WAFER_OPT) $^ --lower-crypto-to-hyper -o $@

$(OUT_DIR)/sha1crack.mlir: SHA1Example.cpp
	@mkdir -p $(@D)
	$(WAFER_FRONTEND) -I $(INC_DIR) -I $(LLVM_CLANG_INC_DIR) \
		 -c $< -o $@

# another way to get op_sha1crack.ll:
# op_sha1crack.ll: SHA1Example.cpp design1.json
# 	$(WAFER_BUILD_DIR)/bin/wafer-frontend -I $(WAFER_DIR)/include -I $(WAFER_DIR)/3rdparty/llvm/build/lib/clang/17/include \
# 	--sst --JsonFilePath ./design1.json -c $< --wafer-to-llvmir -o $@


# Need to write ptx code to "kernel.ptx" in "3rdparty/llvm/mlir/lib/Dialect/GPU/Transforms/SerializeToCubin.cpp"
# TODO: Maybe another way to do this?
$(OUT_DIR)/kernel.ptx: $(OUT_DIR)/gpulaunch.mlir
	$(WAFER_OPT) $< -device-schedule -lower-hyper-memcpy -lower-hyper | \
	$(WAFER_OPT) -lower-crypto-padmessage | \
	$(WAFER_OPT) -lower-cryptosha1-without-SHA1ISA | \
	$(WAFER_OPT) -llvm-request-c-wrappers | \
	$(WAFER_OPT) -convert-scf-to-cf | \
	$(WAFER_OPT) -gpu-kernel-outlining | \
	$(WAFER_OPT) -convert-arith-to-llvm | \
	$(WAFER_OPT) -finalize-memref-to-llvm | \
	$(WAFER_OPT) -convert-vector-to-llvm | \
	$(WAFER_OPT) -pass-pipeline='builtin.module(gpu.module(strip-debuginfo,convert-gpu-to-nvvm,reconcile-unrealized-casts,gpu-to-cubin{chip=sm_30 features=+ptx32}))' > /dev/null

# use cuda 10.1
$(OUT_DIR)/wafer_gpu.out: $(OUT_DIR)/kernel.ptx
	gcc -D__CUDA_ARCH_LIST__=520 -E -x c++ -D__CUDACC__ -D__NVCC__  "-I/usr/local/cuda/bin/../targets/x86_64-linux/include"    -D__CUDACC_VER_MAJOR__=12 -D__CUDACC_VER_MINOR__=0 -D__CUDACC_VER_BUILD__=76 -D__CUDA_API_VER_MAJOR__=12 -D__CUDA_API_VER_MINOR__=0 -D__NVCC_DIAG_PRAGMA_SUPPORT__=1 -include "cuda_runtime.h" -m64 "main.cu" -o "/tmp/tmpxft_0032d7dc_00000000-5_main.cpp4.ii" 
	cudafe++ --c++17 --gnu_version=110300 --display_error_number --orig_src_file_name "main.cu" --orig_src_path_name "/wafer/wyy/mycode/nvcctest/main.cu" --allow_managed  --m64 --parse_templates --gen_c_file_name "/tmp/tmpxft_0032d7dc_00000000-6_main.cudafe1.cpp" --stub_file_name "tmpxft_0032d7dc_00000000-6_main.cudafe1.stub.c" --gen_module_id_file --module_id_file_name "/tmp/tmpxft_0032d7dc_00000000-4_main.module_id" "/tmp/tmpxft_0032d7dc_00000000-5_main.cpp4.ii" 
	gcc -D__CUDA_ARCH__=520 -D__CUDA_ARCH_LIST__=520 -E -x c++  -DCUDA_DOUBLE_MATH_FUNCTIONS -D__CUDACC__ -D__NVCC__  "-I/usr/local/cuda/bin/../targets/x86_64-linux/include"    -D__CUDACC_VER_MAJOR__=12 -D__CUDACC_VER_MINOR__=0 -D__CUDACC_VER_BUILD__=76 -D__CUDA_API_VER_MAJOR__=12 -D__CUDA_API_VER_MINOR__=0 -D__NVCC_DIAG_PRAGMA_SUPPORT__=1 -include "cuda_runtime.h" -m64 "main.cu" -o "/tmp/tmpxft_0032d7dc_00000000-9_main.cpp1.ii" 
	$(CICC) --c++17 --gnu_version=110300 --display_error_number --orig_src_file_name "main.cu" --orig_src_path_name "/wafer/wyy/mycode/nvcctest/main.cu" --allow_managed   -arch compute_52 -m64 --no-version-ident -ftz=0 -prec_div=1 -prec_sqrt=1 -fmad=1 --include_file_name "tmpxft_0032d7dc_00000000-3_main.fatbin.c" -tused --module_id_file_name "/tmp/tmpxft_0032d7dc_00000000-4_main.module_id" --gen_c_file_name "/tmp/tmpxft_0032d7dc_00000000-6_main.cudafe1.c" --stub_file_name "/tmp/tmpxft_0032d7dc_00000000-6_main.cudafe1.stub.c" --gen_device_file_name "/tmp/tmpxft_0032d7dc_00000000-6_main.cudafe1.gpu"  "/tmp/tmpxft_0032d7dc_00000000-9_main.cpp1.ii" -o "/tmp/tmpxft_0032d7dc_00000000-6_main.ptx"
	cp kernel.ptx /tmp/tmpxft_0032d7dc_00000000-6_main.ptx
	ptxas -arch=sm_52 -m64  "/tmp/tmpxft_0032d7dc_00000000-6_main.ptx"  -o "/tmp/tmpxft_0032d7dc_00000000-10_main.sm_52.cubin" 
	fatbinary -64 --cicc-cmdline="-ftz=0 -prec_div=1 -prec_sqrt=1 -fmad=1 " "--image3=kind=elf,sm=52,file=/tmp/tmpxft_0032d7dc_00000000-10_main.sm_52.cubin" "--image3=kind=ptx,sm=52,file=/tmp/tmpxft_0032d7dc_00000000-6_main.ptx" --embedded-fatbin="/tmp/tmpxft_0032d7dc_00000000-3_main.fatbin.c" 
	gcc -D__CUDA_ARCH__=520 -D__CUDA_ARCH_LIST__=520 -c -x c++  -DCUDA_DOUBLE_MATH_FUNCTIONS "-I/usr/local/cuda/bin/../targets/x86_64-linux/include"   -m64 "/tmp/tmpxft_0032d7dc_00000000-6_main.cudafe1.cpp" -o "/tmp/tmpxft_0032d7dc_00000000-11_main.o" 
	nvlink -m64 --arch=sm_52 --register-link-binaries="/tmp/tmpxft_0032d7dc_00000000-7_a_dlink.reg.c"    "-L/usr/local/cuda/bin/../targets/x86_64-linux/lib/stubs" "-L/usr/local/cuda/bin/../targets/x86_64-linux/lib" -cpu-arch=X86_64 "/tmp/tmpxft_0032d7dc_00000000-11_main.o"  -lcudadevrt  -o "/tmp/tmpxft_0032d7dc_00000000-12_a_dlink.sm_52.cubin" --host-ccbin "gcc"
	fatbinary -64 --cicc-cmdline="-ftz=0 -prec_div=1 -prec_sqrt=1 -fmad=1 " -link "--image3=kind=elf,sm=52,file=/tmp/tmpxft_0032d7dc_00000000-12_a_dlink.sm_52.cubin" --embedded-fatbin="/tmp/tmpxft_0032d7dc_00000000-8_a_dlink.fatbin.c" 
	gcc -D__CUDA_ARCH_LIST__=520 -c -x c++ -DFATBINFILE="\"/tmp/tmpxft_0032d7dc_00000000-8_a_dlink.fatbin.c\"" -DREGISTERLINKBINARYFILE="\"/tmp/tmpxft_0032d7dc_00000000-7_a_dlink.reg.c\"" -I. -D__NV_EXTRA_INITIALIZATION= -D__NV_EXTRA_FINALIZATION= -D__CUDA_INCLUDE_COMPILER_INTERNAL_HEADERS__  "-I/usr/local/cuda/bin/../targets/x86_64-linux/include"    -D__CUDACC_VER_MAJOR__=12 -D__CUDACC_VER_MINOR__=0 -D__CUDACC_VER_BUILD__=76 -D__CUDA_API_VER_MAJOR__=12 -D__CUDA_API_VER_MINOR__=0 -D__NVCC_DIAG_PRAGMA_SUPPORT__=1 -m64 "/usr/local/cuda/bin/crt/link.stub" -o "/tmp/tmpxft_0032d7dc_00000000-13_a_dlink.o" 
	g++ -D__CUDA_ARCH_LIST__=520 -m64 -Wl,--start-group "/tmp/tmpxft_0032d7dc_00000000-13_a_dlink.o" "/tmp/tmpxft_0032d7dc_00000000-11_main.o"   "-L/usr/local/cuda/bin/../targets/x86_64-linux/lib/stubs" "-L/usr/local/cuda/bin/../targets/x86_64-linux/lib"  -lcudadevrt  -lcudart_static  -lrt -lpthread  -ldl  -Wl,--end-group -o "wafer_gpu.out" 

$(OUT_DIR)/gpulaunch.mlir: SHA1Example.cpp design1.json
	$(WAFER_BUILD_DIR)/bin/wafer-frontend -I $(WAFER_DIR)/include -I $(WAFER_DIR)/3rdparty/llvm/build/lib/clang/17/include \
	--ptx --JsonFilePath $(DESIGN_JSON_FILE) -c $<  -o $@


.PHONY: openssl
openssl: SHA1Example.cpp
	@mkdir -p build
	$(CXX) -DWAFER_OPENSSL $< -I $(OPENSSL_INC_DIR) -L $(OPENSSL_LIB_DIR) -l crypto -o build/sha1_crack


.PHONY: clean
clean:
	rm -f sha1_host gpulaunch.mlir  graph.json kt_run_exe
	rm -rf *.o
	rm -rf *.out
	rm -rf *.ll
	rm -rf *.s
	rm -rf *.cubin
	rm -rf *.fatbin
	rm -rf _app_cuda_version*
	rm -rf _cuobjdump_list_ptx*
	rm -rf *.ptx
	rm -rf *.ptxas
	rm -rf *.ii
	rm -rf *.fatbin.c
	rm -rf *.module_id
	rm -rf *.cudafe1.c
	rm -rf *.cudafe1.cpp
	rm -rf *.cudafe1.gpu
	rm -rf *.cudafe1.stub.c
	rm -rf *.reg.c
	rm -rf build
	
crack_sha1.ll: gpulaunch.mlir
	${WAFER_OPT} $< -sst-device-schedule  -o $@
